/**
 * 
 */
package im.composer.vapu.rmi.in.receiver;

import java.io.IOException;
import java.rmi.RemoteException;

import im.composer.audio.engine.Out;
import im.composer.vapu.rmi.TimedFloatSampleBuffer;
import im.composer.vapu.rmi.codec.FloatSampleDecoder;

import org.jaudiolibs.audioservers.AudioConfiguration;
import org.tritonus.share.sampled.FloatSampleBuffer;

/**
 * @author david
 * 
 */
public class RmiOutPeer extends Out{

	private RemoteAudioReceiver audioReceiver;
	public RmiOutPeer(AudioConfiguration context) {
		super(context);
	}

	public RmiOutPeer() {
	}

	public RemoteAudioReceiver getAudioReceiver() {
		return audioReceiver;
	}

	public void setAudioReceiver(RemoteAudioReceiver audioReceiver) {
		this.audioReceiver = audioReceiver;
	}

	@Override
	protected void computeBuffer() {
//		System.err.println("t: "+getTime());
		buf.makeSilence();
		try {
			FloatSampleBuffer src = decodeAudio();
			if (src!=null) {
				buf.mix(src);
			}
		} catch (RemoteException e) {
		}
	}

	protected FloatSampleBuffer decodeAudio() throws RemoteException{
		FloatSampleBuffer buf = new FloatSampleBuffer(getContext().getOutputChannelCount(),getBufferSize(),getContext().getSampleRate());
		boolean mixed = false;
		FloatSampleDecoder decoder = audioReceiver.getDecoder();
		long t1 = getTime();
		int offset = 0;
		while(true){
			byte[] b = audioReceiver.poll();
			if(b==null){
				break;
			}

			TimedFloatSampleBuffer tfsb;
			try {
				tfsb = decoder.decode(b);
			} catch (IOException e) {
				continue;
			}
			FloatSampleBuffer buf1 = tfsb.getBuffer();
			if(tfsb.getTimestamp()<0){
				int len = buf1.getSampleCount();
				if(len > buf.getSampleCount() - offset){
					len = buf.getSampleCount() - offset;
				}
				buf.mix(buf1, 0, offset, len);
				mixed = true;
				offset += len;
				if(offset>=buf.getSampleCount()){
					break;
				}
			}else{
				float t2 = tfsb.getTimestamp()*buf1.getSampleCount() / getBufferSize();// what if sample count changed in the middle?
				if(t2<t1){
					continue;
				}
				offset = (int) ((t2-t1) * getBufferSize());
				if(offset>getBufferSize()){
					break;
				}
				buf.mix(buf1, 0, offset, buf1.getSampleCount());
				mixed = true;
				if(offset+buf1.getSampleCount()>getBufferSize()){
					break;
				}
			}
		}
		return mixed?buf:null;
	}

}
